package com.stox.services.data.downloader.manager;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimerTask;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.stox.services.data.downloader.bse.BseExchangeDataDownloader;
import com.stox.services.data.downloader.model.ExchangeDownloadMetadata;
import com.stox.services.data.provider.manager.BarManager;
import com.stox.services.data.provider.manager.ExchangeManager;
import com.stox.services.data.provider.manager.ScripManager;
import com.stox.shared.model.Bar;
import com.stox.shared.model.Exchange;
import com.stox.shared.model.Scrip;
import com.stox.shared.model.enumeration.BarSpan;
import com.stox.shared.model.intf.Callback;
import com.stox.shared.util.Constant;

@Component
@Lazy(false)
public class DownloadManager implements InitializingBean, DisposableBean{
	
	private boolean running;
	private boolean cancelRequested;
	private TimerTask timerTask = new TimerTask(){
		@Override
		public void run() {
			download();
		}
	};
	
	@Autowired
	private BarManager barManager;
	
	@Autowired
	private ScripManager scripManager;
	
	@Autowired
	private ExchangeManager exchangeManager;
	
	@Autowired
	private ExchangeDownloadMetadataManager exchangeDownloadMetadataManager;
	
	/**
	 * TODO Should be made exchange agnostic 
	 */
	private BseExchangeDataDownloader bseExchangeDataDownloader = new BseExchangeDataDownloader();
	
	private Callback<List<Bar>, Void> dataPersistenceCallback = new Callback<List<Bar>, Void>(){
		@Override
		public Void execute(List<Bar> payload) {
			if(null != payload && !payload.isEmpty()){
				Bar bar = payload.get(0);
				if(null != bar && null != bar.getScrip() && null != bar.getScrip().getExchangeId()){
					Long exchangeId = bar.getScrip().getExchangeId();
					
					barManager.save(payload);
					
					List<Scrip> scrips = new ArrayList<>(payload.size());
					for(Bar bar01 : payload){
						scrips.add(bar01.getScrip());
					}
					scripManager.clearSaveAndFlush(scrips);
					
					ExchangeDownloadMetadata exchangeDownloadMetadata = getExchangeDownloadMetadata(exchangeId);
					exchangeDownloadMetadata.setLastDownloadDate(bar.getDate());
					exchangeDownloadMetadataManager.save(exchangeDownloadMetadata);
					System.out.println(exchangeDownloadMetadata);
				}
			}else{
				barManager.flush();
			}
			return null;
		}
	};
	
	@SuppressWarnings("deprecation")
	public Date getDownloadStartDate(){
		return new Date(109, 0, 1);
	}
	
	public ExchangeDownloadMetadata getExchangeDownloadMetadata(Long exchangeId){
		ExchangeDownloadMetadata exchangeDownloadMetaData = 
				exchangeDownloadMetadataManager.findOne(exchangeId);
		if(null == exchangeDownloadMetaData || null == exchangeDownloadMetaData.getLastDownloadDate()){
			exchangeDownloadMetaData = new ExchangeDownloadMetadata();
			exchangeDownloadMetaData.setExchangeId(exchangeId);
			exchangeDownloadMetaData.setLastDownloadDate(getDownloadStartDate());
			exchangeDownloadMetadataManager.save(exchangeDownloadMetaData);
		}
		return exchangeDownloadMetaData;
	}
	
	public void download(){
		if(cancelRequested || running) return;
		try{
			running = true;
			List<Exchange> exchanges = exchangeManager.findAll();
			for(Exchange exchange : exchanges){
				if(cancelRequested) return;
				bseExchangeDataDownloader.download(exchange, BarSpan.DAILY, getExchangeDownloadMetadata(exchange.getId()).getLastDownloadDate(), new Date(), dataPersistenceCallback);
			}
		}finally{
			running = false;
		}
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		Constant.timer.scheduleAtFixedRate(timerTask, 0, 60*1000);
	}
	
	@Override
	public void destroy() throws Exception {
		timerTask.cancel();
		cancelRequested = true;
		bseExchangeDataDownloader.cancel();
	}
}
